package com.delivery.service.impl;


import cn.hutool.core.codec.Base64;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.delivery.dto.WXAuthDto;
import com.delivery.dto.WxPhoneInfoDto;
import com.delivery.entity.User;
import com.delivery.mapper.UserMapper;
import com.delivery.service.IUserService;
import com.delivery.utils.jwtUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.spec.AlgorithmParameterSpec;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 用户信息表 服务实现类
 * </p>
 *
 * @author sixiao
 * @since 2023-04-12
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Value("${wx.mini.appid}")
    private String appid;
    @Value("${wx.mini.secret}")
    private String secret;

    @Autowired
    UserMapper userMapper;


    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private String prefix = "wx_session_id_";

    @Override
    public Map<String,String> getSessionId(String code) {
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code";
        String replaceUrl = url.replace("{0}",appid)
                .replace("{1}",secret)
                .replace("{2}",code);
        String res = HttpUtil.get(replaceUrl);
        String uuid = UUID.randomUUID().toString();
        stringRedisTemplate.opsForValue().set(prefix + uuid,res,30, TimeUnit.MINUTES);
        Map<String,String> map = new HashMap<>();
        map.put("sessionId",uuid);
        return map;
    }


    @Override
    public String authLogin(WXAuthDto wxAuthDto) {
        //1.通过wxauth的值 要对他进行解密
        try {
            //读取session数据
            String json = stringRedisTemplate.opsForValue().get(prefix + wxAuthDto.getSessionId());
            JSONObject jsonObject = JSON.parseObject(json);
            String sessionKey = (String) jsonObject.get("session_key");
            String openId = (String) jsonObject.get("openid");
            Long tokenUserId ;
            //检查数据库有没有唯一的opneid值
            User userByOpenid = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getOpenId, openId));
            if (userByOpenid == null){
                //查询有无此手机号用户  解密
                String s = wxDecrypt(wxAuthDto.getEncryptedData(), sessionKey, wxAuthDto.getIv());
                WxPhoneInfoDto wxPhoneInfoDto = JSON.parseObject(s, WxPhoneInfoDto.class);
                //用户手机号
                String phoneNumber = wxPhoneInfoDto.getPhoneNumber();
                User userByPhonenumber = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getPhonenumber, phoneNumber));
                //此用户为h5时注册用户
                if (userByPhonenumber != null){
                    tokenUserId = userByPhonenumber.getUserId();
                }else {
                    //此用户为新注册用户
                    User user = new User();
                    user.setOpenId(openId);
                    user.setPhonenumber(phoneNumber);
                    user.setStatus(1);
                    user.setLoginDate(new Date());
                    user.setCreateTime(new Date());
                    userMapper.insert(user);  //插入数据库注册用户
                    tokenUserId = user.getUserId();
                }
            }else {
                tokenUserId = userByOpenid.getUserId();
            }
            Map<String,Object> mapUserId =  new HashMap<>();
            mapUserId.put("userId",tokenUserId);
            String token =  jwtUtils.getToken( mapUserId);

            return token;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }

    }

    @Override
    public User getUserByToken(Map<String, Object> map) {
        DecodedJWT decodedJWT =  jwtUtils.verify( map.get("token").toString() );
        String userId = decodedJWT.getClaim("userId").asString();
        User user = userMapper.selectById(userId);

        return user;
    }


    public String wxDecrypt(String encryptData,String sessionKey,String vi) throws Exception {
        byte[] encData = cn.hutool.core.codec.Base64.decode(encryptData);
        byte[] iv =  cn.hutool.core.codec.Base64.decode(vi);
        byte[] key = Base64.decode(sessionKey);
        AlgorithmParameterSpec ivSpec = new IvParameterSpec(iv);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(key,"AES");
        cipher.init(Cipher.DECRYPT_MODE,keySpec,ivSpec);
        return new String(cipher.doFinal(encData),"UTF-8");
    }

}
